﻿using System.Common;
using System.ComponentModel;


namespace System
{
    /// <summary>
    /// 包含了与双精度类型相关的一些常用扩展方法
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Never)]
    public static class DoubleExtension
    {
        /// <summary>
        /// 判断参数是否非数值
        /// </summary>
        /// <param name="number"></param>
        /// <returns></returns>
        public static bool IsNotNumber(this double number)
        {
            return double.IsNaN(number) || double.IsInfinity(number);
        }

        /// <summary>
        /// 判断参数是否是数值
        /// </summary>
        /// <param name="number"></param>
        /// <returns></returns>
        public static bool IsNumber(this double number)
        {
            return !number.IsNotNumber();
        }

        /// <summary>
        /// 值在范围内
        /// </summary>
        /// <param name="value"></param>
        /// <param name="min"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        public static bool InRange(this double value, double min, double max)
        {
            return value >= min && value <= max;
        }

        /// <summary>Checks whether the value is in range or returns the default value</summary>
        /// <param name="value">The Value</param>
        /// <param name="minValue">The minimum value</param>
        /// <param name="maxValue">The maximum value</param>
        /// <param name="defaultValue">The default value</param>
        public static double InRange(this double value, double minValue, double maxValue, double defaultValue)
        {
            return value.InRange(minValue, maxValue) ? value : defaultValue;
        }

        /// <summary>
        /// 在范围内取值
        /// </summary>
        /// <param name="value"></param>
        /// <param name="min"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        public static double ToRange(this double value, double min, double max)
        {
            return Math.Min(Math.Max(value, min), max);
        }

        public static bool IsZero(this double value)
        {
            return Math.Abs(value) < 2.2204460492503131E-15;
        }

        public static double Round(this double value)
        {
            double r = value > 0 ? Math.Ceiling(value) : Math.Floor(value);
            if (Math.Abs(r - value) == 0.5)
                return r;
            else
                return Math.Round(value);
        }

        #region Compare 比较

        /// <summary>
        /// 是否接近
        /// </summary>
        /// <param name="value1"></param>
        /// <param name="value2"></param>
        /// <returns></returns>
        public static bool AreClose(this double value1, double value2)
        {
            if (value1 == value2)
            {
                return true;
            }
            double num2 = ((Math.Abs(value1) + Math.Abs(value2)) + 10.0) * 2.2204460492503131E-16;
            double num = value1 - value2;
            return ((-num2 < num) && (num2 > num));
        }

        public static bool GreaterThan(this double value1, double value2)
        {
            return ((value1 > value2) && !AreClose(value1, value2));
        }

        public static bool LessThan(this double value1, double value2)
        {
            return ((value1 < value2) && !AreClose(value1, value2));
        }

        public static bool LessThanOrClose(this double value1, double value2)
        {
            if (value1 >= value2)
            {
                return AreClose(value1, value2);
            }
            return true;
        }

        public static bool GreaterThanOrClose(this double value1, double value2)
        {
            if (value1 <= value2)
            {
                return AreClose(value1, value2);
            }
            return true;
        }

        #endregion Compare 比较

        #region Memory Size 存储空间大小
        
        private static readonly string[] SizeDefinitions = new[] {
		MemeryUnit.Size_Bytes,
		MemeryUnit.Size_KB,
		MemeryUnit.Size_MB,
		MemeryUnit.Size_GB,
		MemeryUnit.Size_TB
		};

        /// <summary>
        /// 控制尺寸显示转换上限
        /// </summary>
        private static readonly double SizeLevel = 0x400 * 0.9;

        /// <summary>
        /// 转换为尺寸显示方式
        /// </summary>
        /// <param name="size">大小</param>
        /// <returns>尺寸显示方式</returns>
        public static string ToSizeDescription(this double size)
        {
            return ToSizeDescription(size, 2);
        }

        /// <summary>
        /// 转换为尺寸显示方式
        /// </summary>
        /// <param name="size">大小</param>
        /// <param name="digits">小数位数</param>
        /// <returns>尺寸显示方式</returns>
        public static string ToSizeDescription(this double size, int digits)
        {
            var sizeDefine = 0;

            while (sizeDefine < SizeDefinitions.Length && size > SizeLevel)
            {
                size /= 0x400;
                sizeDefine++;
            }

            if (sizeDefine == 0) return size.ToString("#0") + " " + SizeDefinitions[sizeDefine];
            else
            {
                return size.ToString("#0." + string.Empty.PadLeft(digits, '0')) + " " + SizeDefinitions[sizeDefine];
            }
        }

        #endregion Memory Size 存储空间大小

        #region Percent 百分比

        /// <summary>
        /// 获得第一个数字占第二个数字的百分比
        /// </summary>
        /// <param name="first">第一个数字</param>
        /// <param name="second">第二个数字</param>
        /// <returns>百分比-浮点数</returns>
        public static double GetPercentageBy(this double first, double second)
        {
            if (second == 0.0) return 0;

            return first / second;
        }

        /// <summary>
        /// 获得第一个数字占第二个数字的百分比
        /// </summary>
        /// <param name="first">第一个数字</param>
        /// <param name="second">第二个数字</param>
        /// <returns>百分比-浮点数</returns>
        public static decimal GetPercentageBy(this decimal first, decimal second)
        {
            if (second == 0.0m) return 0;

            return first / second;
        }

        #endregion Percent 百分比

        #region ToString 转换字符串

        /// <summary>
        /// 显示为字符串
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string ToDisplayString(this double? value)
        {
            return value == null ? "" : value.ToString();
        }

        /// <summary>
        /// 显示为字符串
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string ToDisplayString(this double? value, string defaultDisplayString)
        {
            return value == null ? defaultDisplayString : value.ToString();
        }

        #endregion ToString 转换字符串
    }
}